package hw2.jpa.ejb.model;

import hw2.jpa.ejb.mf.wrapper.MfDate;
import hw2.jpa.ejb.mf.wrapper.Money;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

@Entity
public class Contract implements Serializable {

	private static final long serialVersionUID = 1L;

	@Id
	@GeneratedValue
	private Long id;
	@Embedded
	private Money revenue;
	@Embedded
	private MfDate whenSigned;

	@ManyToOne(cascade = { CascadeType.ALL })
	private Product product;

	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
	private List<RevenueRecognition> revenueRecognitions = new ArrayList<RevenueRecognition>();

	public Contract() {
	}

	public Contract(Product product, Money revenue, MfDate whenSigned) {
		super();
		this.product = product;
		this.revenue = revenue;
		this.whenSigned = whenSigned;
	}

	public Money recognizedRevenue(MfDate asOf) {
		Money result = Money.dollars(0);
		Iterator<RevenueRecognition> it = revenueRecognitions.iterator();
		while (it.hasNext()) {
			RevenueRecognition recognition = (RevenueRecognition) it.next();
			if (recognition.isRecognizableBy(asOf)) {
				result = result.add(recognition.getAmount());
			}
		}
		return result;
	}

	public void addRevenueRecognition(RevenueRecognition revenueRecognition) {
		revenueRecognitions.add(revenueRecognition);

	}

	public void calculateRecognitions() {
		product.calculateRevenueRecognitions(this);
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public Money getRevenue() {
		return revenue;
	}

	public void setRevenue(Money revenue) {
		this.revenue = revenue;
	}

	public MfDate getWhenSigned() {
		return whenSigned;
	}

	public void setWhenSigned(MfDate whenSigned) {
		this.whenSigned = whenSigned;
	}

	public Product getProduct() {
		return product;
	}

	public void setProduct(Product product) {
		this.product = product;
	}

	public List<RevenueRecognition> getRevenueRecognitions() {
		return revenueRecognitions;
	}

	public void setRevenueRecognitions(
			List<RevenueRecognition> revenueRecognitions) {
		this.revenueRecognitions = revenueRecognitions;
	}

	@Override
	public String toString() {
		return this.id + ":" + this.product.getName() + ":"
				+ this.revenue.amount() + ":" + this.whenSigned.toSqlDate();
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((product == null) ? 0 : product.hashCode());
		result = prime * result + ((revenue == null) ? 0 : revenue.hashCode());
		result = prime * result
				+ ((whenSigned == null) ? 0 : whenSigned.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Contract)) {
			return false;
		}
		Contract other = (Contract) obj;
		if (id == null) {
			if (other.id != null) {
				return false;
			}
		} else if (!id.equals(other.id)) {
			return false;
		}
		if (product == null) {
			if (other.product != null) {
				return false;
			}
		} else if (!product.equals(other.product)) {
			return false;
		}
		if (revenue == null) {
			if (other.revenue != null) {
				return false;
			}
		} else if (!revenue.equals(other.revenue)) {
			return false;
		}
		if (whenSigned == null) {
			if (other.whenSigned != null) {
				return false;
			}
		} else if (!whenSigned.equals(other.whenSigned)) {
			return false;
		}
		return true;
	}

}
